
package DBM;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;

/**
 * DatabaseManager.java
 * 
 * @version 1.0
 *          - Make connection
 *          - Close connection
 *          - Create prepared statement
 * @version 1.1
 *          - Make connection with a configfile
 *          - Exception handler and write to file
 * 
 * @author Kenny
 * 
 *         This database manager is made for mysql.
 *         Using 'mysql-connector-java-5.1.18-bin.jar'
 * 
 */
public class DBManager {
	private Connection			con				= null;
	@SuppressWarnings( "unused" )
	private Driver				driver			= null;
	private String				errorFilePath	= "./stacktrace.txt";
	private String				dbAdress;
	private String				dbName;
	private String				dbInlogName;
	private String				dbPassword;
	private static final String	drivers			= "com.mysql.jdbc.Driver";
	private static Properties	configFile;
	private File				errorFile;

	/**
	 * Creates a database manager which includes a database connection
	 * 
	 * @param dbAdress
	 *            Ip-adress of the database
	 * @param dbName
	 *            Database namer
	 * @param dbInlogName
	 *            Inlog name for the database
	 *            If there is no connection, this method will connect
	 *            to the database
	 * @param statement
	 *            Statement you want to execute
	 * @param dbPassword
	 *            Password for the database
	 */
	public DBManager( String dbAdress, String dbName, String dbInlogName,
			String dbPassword ) {
		this.dbAdress = dbAdress;
		this.dbName = dbName;
		this.dbInlogName = dbInlogName;
		this.dbPassword = dbPassword;
		startDb( dbAdress, dbName, dbInlogName, dbPassword );
	}

	/**
	 * Creates a database manager which includes a database connection
	 * using the "configfile.cfg"
	 */
	public DBManager() {
		configFile = new Properties();
		try {
			configFile.load( this.getClass().getClassLoader()
					.getResourceAsStream( "configfile.cfg" ) );
			dbAdress = configFile.getProperty( "dbAdress" );
			dbName = configFile.getProperty( "dbName" );
			dbInlogName = configFile.getProperty( "dbInlogName" );
			dbPassword = configFile.getProperty( "dbPassword" );
			startDb( dbAdress, dbName, dbInlogName, dbPassword );
		} catch( IOException e ) {
			System.err
					.println( "EXCEPTION: DatabaseManager -> DatabaseManager(...): IOException!" );
			saveError( e );
		}
	}

	/**
	 * Writes the exception to an file.
	 * Make sure the file exists!
	 * 
	 * @param exception
	 *            The exception that occured
	 */
	private void saveError( Exception exception ) {
		try {
			errorFile = new File( errorFilePath );
			PrintWriter out = new PrintWriter( new FileOutputStream( errorFile ) );
			exception.printStackTrace( out );
			out.close();
		} catch( FileNotFoundException saveErrorFailed ) {
			System.err
					.println( "EXCEPTION: DatabaseManager -> saveError(...): FileNotFoundException!" );
			exception.printStackTrace();
			saveErrorFailed.printStackTrace();
		}
	}

	/**
	 * Starts a connection to the database
	 * 
	 * @param dbAdress
	 *            Ip-adress of the database
	 * @param dbName
	 *            Database namer
	 * @param dbInlogName
	 *            Inlog name for the database
	 * @param dbPassword
	 *            Password for the database
	 */
	private void startDb( String dbAdress, String dbName, String dbInlogName,
			String dbPassword ) {
		try {
			con = createConnection( dbAdress, dbName, dbInlogName, dbPassword );
		} catch( Exception e ) {
			System.err
					.println( "EXCEPTION: DatabaseManager -> startDb(...): Exception!" );
			saveError( e );
		}
	}

	/**
	 * Creates a connection to the database
	 * 
	 * @param dbAdress
	 *            Ip-adress of the database
	 * @param dbName
	 *            Database namer
	 * @param dbInlogName
	 *            Inlog name for the database
	 * @param dbPassword
	 *            Password for the database
	 * @return A database connection
	 */
	private Connection createConnection( String dbAdress, String dbName,
			String dbInlogName, String dbPassword ) {
		// System.out.println( "create connection to: " + dbAdress + "/" +
		// dbName + " -> login name: '" + dbInlogName + "', password: '" +
		// dbPassword + "'" );
		if( drivers != null ) {
			try {
				driver = (java.sql.Driver) Class.forName( drivers )
						.newInstance();
				return DriverManager.getConnection( "jdbc:mysql://" + dbAdress
						+ "/" + dbName, dbInlogName, dbPassword );
			} catch( InstantiationException e ) {
				System.err
						.println( "EXCEPTION: DatabaseManager -> createConnection(...): InstantiationException!" );
				saveError( e );
			} catch( IllegalAccessException e ) {
				System.err
						.println( "EXCEPTION: DatabaseManager -> createConnection(...): IllegalAccessException!" );
				saveError( e );
			} catch( ClassNotFoundException e ) {
				System.err
						.println( "EXCEPTION: DatabaseManager -> createConnection(...): ClassNotFoundException!" );
				saveError( e );
			} catch( SQLException e ) {
				System.err
						.println( "EXCEPTION: DatabaseManager -> createConnection(...): SQLException!" );
				saveError( e );
			}
		}
		System.out
				.println( "DatabaseManager -> createConnection(...): returning NULL!" );
		return null;
	}

	/**
	 * Closes the connection to the database
	 */
	public void closeConnection() {
		try {
			con.close();
			con = null;
		} catch( SQLException e ) {
			System.err
					.println( "EXCEPTION: DatabaseManager -> closeConnection(): SQLException!" );
			saveError( e );
		}
	}

	/**
	 * Returns the connection to the database
	 * 
	 * @return Connection A database connection
	 */
	public Connection getConnection() {
		return con;
	}

	/**
	 * Creates a prepared statement
	 * If there is no connection, this method will connect
	 * to the database
	 * 
	 * @param statement
	 *            Statement you want to execute
	 * @return A prepared statement
	 */
	public PreparedStatement makePreparedStatement( String statement ) {
		try {
			if( con == null ) {
				con = createConnection( dbAdress, dbName, dbInlogName,
						dbPassword );
			} else if( con.isClosed() ) {
				con = createConnection( dbAdress, dbName, dbInlogName,
						dbPassword );
			}
			PreparedStatement ppstm = con.prepareStatement( statement );
			return ppstm;
		} catch( SQLException e ) {
			System.err
					.println( "EXCEPTION: DatabaseManager -> makePreparedStatement(...): SQLException!" );
			saveError( e );
		}
		return null;
	}
}
